package cn.player.download;

import android.util.Log;

import java.io.File;
import java.io.FileFilter;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;

import cntv.player.core.util.LogUtil;


public class DownloadThreadPool extends ThreadPoolExecutor {


    public static final int DOWNLOAD_START_SUCCESS = 1;
    public static final int DOWNLOAD_START_ERR = -1;  //出错
    public static final int DOWNLOAD_START_NO_MORE_SIZE = -2;  //空间不足
    public static final int DOWNLOAD_START_NO_SDCARD = -3;  //没sd卡
    public static final int DOWNLOAD_START_NET_ERR = -4; //网络错误

    private static final String TAG = "DownloadThreadPool";
    private static int corePoolSize;//核心线程，最小线程数
    private static int maxPoolSize;//最大线程数
    private static int queueCapacity;//工作队列长度
    private static BlockingQueue<Runnable> workQueue; // 工作队列
    private static long keepAliveTime = 3;// 线程空闲最长时间
    private static DownloadThreadPool pool = null;

    static {
        corePoolSize = getCPUCores() == 1 ? 4 : getCPUCores() * 2;    //核心线程数等于当前系统的cpu核心数，至少维护2个核心线程
        queueCapacity = corePoolSize;//维护与核心线程数量相等个数的等待任务
        maxPoolSize = corePoolSize + 8;//维护8个应急线程
    }

    /**
     * @param corePoolSize    池中所保存的线程数，包括空闲线程
     * @param maximumPoolSize 池中允许的最大线程数
     * @param keepAliveTime   当线程数大于corePoolSize核心线程时，此为终止前多余的空闲线程等待新任务的最长时间
     * @param unit            参数的时间单位
     * @param workQueue       执行前用于保持任务的队列,此队列仅保持由 execute方法提交的 Runnable任务
     * @param handler         超出线程范围和队列容量而使执行被阻塞时所使用的处理程序
     */
    private DownloadThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
    }

    /**
     * 获取线程池实例，
     *
     * @return
     */
    public static synchronized DownloadThreadPool getInstance() {
        if (pool == null) {
            workQueue = new PriorityBlockingQueue<>(queueCapacity);//可设置优先级任务的阻塞队列e
            pool = new DownloadThreadPool(corePoolSize, maxPoolSize, keepAliveTime, TimeUnit.SECONDS, workQueue, new CallerRunsPolicy());
        }
        return pool;
    }


    @Override
    protected void beforeExecute(Thread t, Runnable r) {
        // TODO Auto-generated method stub
//        DownloadFileTask task = (DownloadFileTask)r;
//        task.getEntity().getFilename();
//        LogUtil.u("DownloadThreadPool beforeExecute() getActiveCount() = " + getActiveCount()  + ",getQueue().size()=" + getQueue().size() + ",filename = " + task.getEntity().getFilename());
        super.beforeExecute(t, r);
    }

    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        // TODO Auto-generated method stub
        super.afterExecute(r, t);
//        LogUtil.u("DownloadThreadPool afterExecute() Thread name = " + r.toString());

        DownloadFileTask task = (DownloadFileTask)r;
        if(task.getEntity().getDownloadState() != DownloadInfo.DOWNLOAD_SUCCESS){
            LogUtil.u("任务异常....,filename = " + task.getEntity().getFilename());
            task.updateDownloadInfoState(DOWNLOAD_START_ERR);
        }
    }


    /**
     * 获取CPU核心数
     *
     * @return
     */
    private static int getCPUCores() {
        //Private Class to display only CPU devices in the directory listing
        class CpuFilter implements FileFilter {
            @Override
            public boolean accept(File pathname) {
                //Check if filename is "cpu", followed by a single digit number
                if (Pattern.matches("cpu[0-9]", pathname.getName())) {
                    return true;
                }
                return false;
            }
        }
        try {
            //Get directory containing CPU info
            File dir = new File("/sys/devices/system/cpu/");
            //Filter to only list the devices we care about
            File[] files = dir.listFiles(new CpuFilter());
//	        Log.d(TAG, "CPU Count: "+files.length);
            //Return the number of cores (virtual CPU devices)
            return files.length;
        } catch (Exception e) {
            //Print exception
            Log.d(TAG, "CPU Count: Failed.");
            e.printStackTrace();
            //Default to return 1 core
            return 1;
        }
    }
}
